package com.qianfeng.microservice.zuul.filters;

//
//                            _ooOoo_
//                           o8888888o
//                           88" . "88
//                           (| -_- |)
//                            O\ = /O
//                        ____/`---'\____
//                      .   ' \\| |// `.
//                       / \\||| : |||// \
//                     / _||||| -:- |||||- \
//                       | | \\\ - /// | |
//                     | \_| ''\---/'' | |
//                      \ .-\__ `-` ___/-. /
//                   ___`. .' /--.--\ `. . __
//                ."" '< `.___\_<|>_/___.' >'"".
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |
//                 \ \ `-. \_ __\ /__ _/ .-` / /
//         ======`-.____`-.___\_____/___.-`____.-'======
//                            `=---='
//
//         .............................................
//                  佛祖镇楼                  BUG辟易
//          佛曰:
//                  写字楼里写字间，写字间里程序员；
//                  程序人员写程序，又拿程序换酒钱。
//                  酒醒只在网上坐，酒醉还来网下眠；
//                  酒醉酒醒日复日，网上网下年复年。
//                  但愿老死电脑间，不愿鞠躬老板前；
//                  奔驰宝马贵者趣，公交自行程序员。
//                  别人笑我忒疯癫，我笑自己命太贱；
//


import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.qianfeng.microservice.zuul.pojo.ApiEntiy;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Jackiechan on 2022/9/23 20:05
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@Component
public class MyPreFilter extends ZuulFilter {

    private static Map<String, ApiEntiy> routes = new ConcurrentHashMap<>();

    static {
       // routes.put("user.info", new ApiEntiy("userservice-v2", "/users/user/{id}"));
        routes.put("user2.info", new ApiEntiy("userservice-v2", "/users/user2/{id}"));
        routes.put("user.test", new ApiEntiy("userservice-v2", "/users/test3"));
    }

    /**
     * 必须返回数据,不然会出现空指针
     * @return
     */
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        //我们自定义前置过滤器的有限期尽量大于等于6
        return FilterConstants.PRE_DECORATION_FILTER_ORDER+1;
    }

    /**
     * 根据我们的业务的实际情况来决定是不是启用
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取前面的过滤器有没有拦截
        boolean sendZuulResponse = currentContext.sendZuulResponse();
        return sendZuulResponse;
    }

    @Override
    public Object run() throws ZuulException {
        System.err.println("MyPreFilter中的方法run 执行了--->");
        //用户的请求过来,我们一般要处理数据,数据大部分都在请求中
        //获取当前的请求上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取我们的请求对象
        HttpServletRequest request = currentContext.getRequest();
        request.getParameterMap().keySet().forEach(System.err::println);
        //获取响应对象
      //  HttpServletResponse response = currentContext.getResponse();

        //拦截请求,实际上这个方法不会带来任何拦截效果,除非我们响应了这个数据
        //currentContext.setSendZuulResponse(false);

//        try {
//
//            //我们通过响应返回数据,会报错,为什么呢?我们在这里使用了getwriter,
//            // 请求会继续向下传递,到达目标服务,然后返回结果给我们的网关,网关会调用post过滤器将结果返回给用户,
//            // 需要再次 调用getwriter,就会导致重复使用,报错
//            //正常来说我们只有拦截请求不让它继续下去的时候才会通过当前过滤器返回数据
//            response.getWriter().write("zhe shi fan hui jie guo ");
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
        //设置响应正文,等价于上面的response.getWriter().write,不同的地方是,即便我们没有拦截请求,这个操作也会覆盖原始的返回结果
      //  currentContext.setResponseBody("zhe shi xiang ying zheng wen ");
        //在过滤器之间传递数据,只能从前往后传递
        currentContext.set("canshuming","参数值");
        //强制转发请求到新的服务个地址,要注意当前过滤器的优先级必须大于等于6,因为程序中除了我们的过滤器之外还有默认的过滤器
        //我们如果优先级很很高,然后篡改了数据,会导致出现空指针
     //   currentContext.set(FilterConstants.SERVICE_ID_KEY, "userservice-v2");
        //currentContext.set(FilterConstants.REQUEST_URI_KEY,"/users/user/2");


        //我们需要将请求转发到用户想要的服务上面,我们要求用户必须通过method参数来传递想要的服务的标识
        //我们根据标识查询出服务真正的id和地址,然后将请求转发过去
        String method = request.getParameter("method");
        //我们的业务要求没有传递method就拦截请求
        if (!StringUtils.hasText(method)) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody("没有传递method");
            return null;
        }
        //根据用户传递的key获取到想要的服务的数据
        ApiEntiy apiEntiy = routes.get(method);
        if (apiEntiy == null) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody("请传递正确的请求参数");
            return null;
        }
        currentContext.set(FilterConstants.SERVICE_ID_KEY, apiEntiy.getServiceId());
        //我们发现我们传递的参数不对,我们把{id}传过去了,但是实际上这个在我们这边是一个占位符,我们期望在实际情况中应该替换成真正的值,然后传递过去
        //我们发现我们不知道要将什么参数替换掉占位符,因为我们的占位符会可能有多个,也可能没有, 传递的实际参数可能有多个,也可能没有
        //但是我们可以确定一个事情,就是这些需要的参数一定是用户传递过来的,所以我们需要通过某种方式知道用户传递的参数和占位符之间的关系
        //我们发现就是需要知道A对应B这种关系,而这种关系要么就是map,要么就是一致性,比如我们占位符的名字和用户传递的对应的参数的名字一样
        //比如 我们有占位符/{id}/{name} 那么用必须通过id=xxx&name=xxx的方式来传递参数,这样两个id是对应的,两个name是对应的
        //我们就可以获取到所有用户传递的参数,直接遍历,用传递的值,替换掉这个参数对应的占位符
        //获取到用户传递的所有的参数名
        Enumeration<String> parameterNames = request.getParameterNames();
        String uri = apiEntiy.getRequestUri();
        System.err.println("替换前的uri==>" + uri);
        //循环替换
        while (parameterNames.hasMoreElements()) {
            //每一个参数名
            String parterName = parameterNames.nextElement();
            //替换数据
            uri = uri.replace("{" + parterName + "}", request.getParameter(parterName));
        }
        System.err.println("替换后的uri==>" + uri);
        currentContext.set(FilterConstants.REQUEST_URI_KEY,uri);

        return null;
    }
}
